package alarm;

import java.util.Arrays;
import java.util.List;

import org.snmp4j.PDU;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.UnsignedInteger32;
import org.snmp4j.smi.VariableBinding;

import features.SNMPClient;
import features.SNMPException;
import features.SNMPSession;
import features.SNMPValue;

public class Alarm {
	private static final String VARIABLE_INDEX = 	".1.3.6.1.2.1.16.3.1.1.1";
	private static final String INTERVAL = 			".1.3.6.1.2.1.16.3.1.1.2";
	private static final String VARIABLE = 			".1.3.6.1.2.1.16.3.1.1.3";
	private static final String SAMPLETYPE = 		".1.3.6.1.2.1.16.3.1.1.4";
	public static final String ALARMVALUE = 		".1.3.6.1.2.1.16.3.1.1.5"; //read-only
	private static final String STARTUPVALUE = 		".1.3.6.1.2.1.16.3.1.1.6";
	private static final String RISINGTHRESHOLD = 	".1.3.6.1.2.1.16.3.1.1.7";
	private static final String FALLINGTHRESHOLD = 	".1.3.6.1.2.1.16.3.1.1.8";
	private static final String RISINGEVENTINDEX = 	".1.3.6.1.2.1.16.3.1.1.9";
	private static final String FALLINGEVENTINDEX = ".1.3.6.1.2.1.16.3.1.1.10";
	private static final String OWNER = 			".1.3.6.1.2.1.16.3.1.1.11";
	public static final String STATUS = 			".1.3.6.1.2.1.16.3.1.1.12";
	
	private UnsignedInteger32 variableIndex; //variableIndex > 1
	private Integer32 interval;
	private OID variable;
	private SampleType sampleType; 	//absoluteValue(1), deltaValue(2)
	private Integer32 alarmValue; //read-only
	private StartupAlarm startupAlarm; 	// risingAlarm(1), fallingAlarm(2), risingOrFallingAlarm(3)
	private Integer32 risingThreshold;
	private Integer32 fallingThreshold;
	private Integer32 risingEventIndex; //optional
	private Integer32 fallingEventIndex; //optional
	private OctetString owner; //optional
	private AlarmStatus status = AlarmStatus.createRequest; 		//valid(1), createRequest(2), underCreation(3), invalid(4)
	private String targetIp; //solo per indetificare il msg nel sistema
	private SNMPSession session;

	public Alarm() {}
	
	private int getFreeIndex(SNMPSession session) throws SNMPException {
		int freeIndex = 1;
		List<SNMPValue> indexes = session.getColumn(VARIABLE_INDEX);
		int[] indexesInt = new int[indexes.size()];
		
		for (int i = 0; i < indexes.size(); i++) {
			indexesInt[i] = indexes.get(i).toInt();
		}
		Arrays.sort(indexesInt);
		
		for (int i = 0; i < indexesInt.length; i++) {
			if(freeIndex != indexesInt[i])
				return freeIndex;
			else
				freeIndex++;
		}
		
		return freeIndex;
	}
	
	public void register(SNMPSession session) throws SNMPException {
		this.session = session;
		PDU pdu = null;
		int index = getFreeIndex(session);
		
		this.variableIndex = new UnsignedInteger32(index);
		
		pdu = new PDU();
		pdu.add(new VariableBinding(new OID(STATUS + "." + index), AlarmStatus.createRequest.toVariable()));
		
		pdu = new PDU();
		pdu.add(new VariableBinding(new OID(INTERVAL + "." + index), interval));
		session.set(pdu);
		
		pdu = new PDU();
		pdu.add(new VariableBinding(new OID(VARIABLE + "." + index), variable));
		session.set(pdu);
		
		pdu = new PDU();
		pdu.add(new VariableBinding(new OID(SAMPLETYPE + "." + index), sampleType.toVariable()));
		session.set(pdu);
		
//		pdu = new PDU();
//		pdu.add(new VariableBinding(new OID(ALARMVALUE + "." + index), alarmValue));
//		session.set(pdu);
		
		pdu = new PDU();
		pdu.add(new VariableBinding(new OID(STARTUPVALUE + "." + index), startupAlarm.toVariable()));
		session.set(pdu);
		
		if(risingEventIndex != null) {
			pdu = new PDU();
			pdu.add(new VariableBinding(new OID(RISINGEVENTINDEX + "." + index), risingEventIndex));
			session.set(pdu);
		}
		
		pdu = new PDU();
		pdu.add(new VariableBinding(new OID(RISINGTHRESHOLD + "." + index), risingThreshold));
		session.set(pdu);
		
		pdu = new PDU();
		pdu.add(new VariableBinding(new OID(FALLINGTHRESHOLD + "." + index), fallingThreshold));
		session.set(pdu);
		
		if(fallingEventIndex != null) {
			pdu = new PDU();
			pdu.add(new VariableBinding(new OID(FALLINGEVENTINDEX + "." + index), fallingEventIndex));
			session.set(pdu);
		}
		
		if(owner != null) {
			pdu = new PDU();
			pdu.add(new VariableBinding(new OID(OWNER + "." + index), new OctetString(owner.toString())));
			session.set(pdu);
		}
		
		pdu = new PDU();
		pdu.add(new VariableBinding(new OID(STATUS + "." + index), AlarmStatus.valid.toVariable()));
		session.set(pdu);
		
	}
	
	public void unregister() {
		PDU pdu = new PDU();
		pdu.add(new VariableBinding(new OID(STATUS + "." + variableIndex.toInt()), AlarmStatus.invalid.toVariable()));
		
		session.set(pdu);
	}
	
	public static void unregisterAllAlarm(SNMPSession session) throws SNMPException {
		PDU pdu = null;
		List<SNMPValue> indexes = session.getColumn(VARIABLE_INDEX);
		for (SNMPValue value : indexes) {
			System.out.println("Index: " + value.toInt());
			pdu = new PDU();
			pdu.add(new VariableBinding(new OID(STATUS + "." + value.toInt()), AlarmStatus.invalid.toVariable()));
			
			ResponseEvent resp = session.set(pdu);
			if(resp.getError() != null)
				System.out.println(resp.getError().getMessage());
			if(resp.getResponse() != null)
				System.out.println(PDU.toErrorStatusText(resp.getResponse().getErrorStatus()));
		}
	}
	
	public static void main(String[] args) throws SNMPException {
		SNMPSession session = SNMPClient.startSession(SNMPClient.VERSION_2C);
		session.init("192.2.1.1", SNMPClient.DEFAULT_PORT_STRING, SNMPClient.DEFAULT_COMMUNITY);
		
		unregisterAllAlarm(session);
	}
	
//	public PDU toPDU() {
//		PDU pdu = new PDU();
//		pdu.setType(PDU.SET);
//		
//		if(variableIndex != null) //Forse e' obbligatorio
//			pdu.add(new VariableBinding(VARIABLE_INDEX, variableIndex));
//		pdu.add(new VariableBinding(INTERVAL, interval));
//		pdu.add(new VariableBinding(VARIABLE, variable));
//		pdu.add(new VariableBinding(SAMPLETYPE, sampleType.toVariable()));
////		pdu.add(new VariableBinding(ALARMVALUE, alarmValue));
//		pdu.add(new VariableBinding(STARTUPVALUE, startupAlarm.toVariable()));
//		pdu.add(new VariableBinding(RISINGTHRESHOLD, risingThreshold));
//		pdu.add(new VariableBinding(FALLINGTHRESHOLD, fallingThreshold));
//		
//		if(risingEventIndex != null)
//			pdu.add(new VariableBinding(RISINGEVENTINDEX, risingEventIndex));
//		
//		if(fallingEventIndex != null)
//			pdu.add(new VariableBinding(FALLINGEVENTINDEX, fallingEventIndex));
//		
//		if(owner != null)
//			pdu.add(new VariableBinding(OWNER, owner));
//		
//		pdu.add(new VariableBinding(STATUS, status.toVariable()));
//		
//		
//		return pdu;
//	}
	
	/**
	 * Crea unb nuovo Alarm a partire dal PDU ricevuto
	 * @param pdu
	 * @return nuovo Alarm
	 */
//	@SuppressWarnings("unchecked")
//	public static Alarm fromPDU(PDU pdu) {
//		Alarm alarm = new Alarm();
//		List<VariableBinding> bindings = (List<VariableBinding>) pdu.getVariableBindings();
//		for (VariableBinding variableBinding : bindings) {
//			OID oid = variableBinding.getOid();
//			Variable variable = variableBinding.getVariable();
//			if(oid.compareTo(VARIABLE_INDEX) == 0) {
//				alarm.setFallingEventIndex((UnsignedInteger32) variable);
//			} else if(oid.compareTo(VARIABLE_INDEX) == 0) {
//				alarm.setFallingThreshold((Integer32) variable);
//			} else if(oid.compareTo(VARIABLE_INDEX) == 0) {
//				alarm.setInterval((Integer32) variable);
//			} else if(oid.compareTo(VARIABLE_INDEX) == 0) {
//				alarm.setOwner((OctetString) variable);
//			} else if(oid.compareTo(VARIABLE_INDEX) == 0) {
//				alarm.setRisingEventIndex((UnsignedInteger32) variable);
//			} else if(oid.compareTo(VARIABLE_INDEX) == 0) {
//				alarm.setRisingThreshold((Integer32) variable);
//			} else if(oid.compareTo(VARIABLE_INDEX) == 0) {
//				alarm.setSampleType(SampleType.fromVariable((Integer32) variable));
//			} else if(oid.compareTo(VARIABLE_INDEX) == 0) {
//				alarm.setStartupAlarm(StartupAlarm.fromVariable((Integer32) variable));
//			} else if(oid.compareTo(VARIABLE_INDEX) == 0) {
//				alarm.setStatus(AlarmStatus.fromVariable((Integer32) variable));
//			} else if(oid.compareTo(VARIABLE_INDEX) == 0) {
//				alarm.setVariable((OID) variable);
//			}
//		}
//		
//		return alarm;
//	}

	public Integer32 getInterval() {
		return interval;
	}

	public void setInterval(Integer32 interval) {
		this.interval = interval;
	}

	public OID getVariable() {
		return variable;
	}

	public void setVariable(OID variable) {
		this.variable = variable;
	}

	public SampleType getSampleType() {
		return sampleType;
	}

	public void setSampleType(SampleType sampleType) {
		this.sampleType = sampleType;
	}

	public StartupAlarm getStartupAlarm() {
		return startupAlarm;
	}

	public void setStartupAlarm(StartupAlarm startupAlarm) {
		this.startupAlarm = startupAlarm;
	}

	public Integer32 getRisingThreshold() {
		return risingThreshold;
	}

	public String getTargetIp() {
		return targetIp;
	}

	public void setTargetIp(String targetIp) {
		this.targetIp = targetIp;
	}
	
	public void setRisingThreshold(Integer32 risingThreshold) {
		this.risingThreshold = risingThreshold;
	}

	public Integer32 getFallingThreshold() {
		return fallingThreshold;
	}

	public void setFallingThreshold(Integer32 fallingThreshold) {
		this.fallingThreshold = fallingThreshold;
	}

	public Integer32 getRisingEventIndex() {
		return risingEventIndex;
	}

	public void setRisingEventIndex(Integer32 risingEventIndex) {
		this.risingEventIndex = risingEventIndex;
	}

	public Integer32 getFallingEventIndex() {
		return fallingEventIndex;
	}

	public void setFallingEventIndex(Integer32 fallingEventIndex) {
		this.fallingEventIndex = fallingEventIndex;
	}

	public OctetString getOwner() {
		return owner;
	}

	public void setOwner(OctetString owner) {
		this.owner = owner;
	}

	public AlarmStatus getStatus() {
		return status;
	}

	public UnsignedInteger32 getVariableIndex() {
		return variableIndex;
	}

	public void setVariableIndex(UnsignedInteger32 variableIndex) {
		this.variableIndex = variableIndex;
	}

	public Integer32 getAlarmValue() {
		return alarmValue;
	}

	public void setAlarmValue(Integer32 alarmValue) {
		this.alarmValue = alarmValue;
	}

	public void setStatus(AlarmStatus status) {
		this.status = status;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((alarmValue == null) ? 0 : alarmValue.hashCode());
		result = prime * result + ((fallingEventIndex == null) ? 0 : fallingEventIndex.hashCode());
		result = prime * result + ((fallingThreshold == null) ? 0 : fallingThreshold.hashCode());
		result = prime * result + ((interval == null) ? 0 : interval.hashCode());
		result = prime * result + ((owner == null) ? 0 : owner.hashCode());
		result = prime * result + ((risingEventIndex == null) ? 0 : risingEventIndex.hashCode());
		result = prime * result + ((risingThreshold == null) ? 0 : risingThreshold.hashCode());
		result = prime * result + ((sampleType == null) ? 0 : sampleType.hashCode());
		result = prime * result + ((startupAlarm == null) ? 0 : startupAlarm.hashCode());
		result = prime * result + ((status == null) ? 0 : status.hashCode());
		result = prime * result + ((targetIp == null) ? 0 : targetIp.hashCode());
		result = prime * result + ((variable == null) ? 0 : variable.hashCode());
		result = prime * result + ((variableIndex == null) ? 0 : variableIndex.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof Alarm))
			return false;
		final Alarm other = (Alarm) obj;
		if (alarmValue == null) {
			if (other.alarmValue != null)
				return false;
		} else if (!alarmValue.equals(other.alarmValue))
			return false;
		if (fallingEventIndex == null) {
			if (other.fallingEventIndex != null)
				return false;
		} else if (!fallingEventIndex.equals(other.fallingEventIndex))
			return false;
		if (fallingThreshold == null) {
			if (other.fallingThreshold != null)
				return false;
		} else if (!fallingThreshold.equals(other.fallingThreshold))
			return false;
		if (interval == null) {
			if (other.interval != null)
				return false;
		} else if (!interval.equals(other.interval))
			return false;
		if (owner == null) {
			if (other.owner != null)
				return false;
		} else if (!owner.equals(other.owner))
			return false;
		if (risingEventIndex == null) {
			if (other.risingEventIndex != null)
				return false;
		} else if (!risingEventIndex.equals(other.risingEventIndex))
			return false;
		if (risingThreshold == null) {
			if (other.risingThreshold != null)
				return false;
		} else if (!risingThreshold.equals(other.risingThreshold))
			return false;
		if (sampleType == null) {
			if (other.sampleType != null)
				return false;
		} else if (!sampleType.equals(other.sampleType))
			return false;
		if (startupAlarm == null) {
			if (other.startupAlarm != null)
				return false;
		} else if (!startupAlarm.equals(other.startupAlarm))
			return false;
		if (status == null) {
			if (other.status != null)
				return false;
		} else if (!status.equals(other.status))
			return false;
		if (targetIp == null) {
			if (other.targetIp != null)
				return false;
		} else if (!targetIp.equals(other.targetIp))
			return false;
		if (variable == null) {
			if (other.variable != null)
				return false;
		} else if (!variable.equals(other.variable))
			return false;
		if (variableIndex == null) {
			if (other.variableIndex != null)
				return false;
		} else if (!variableIndex.equals(other.variableIndex))
			return false;
		return true;
	}
	
	
}
